﻿// -------------------------------------------------------------------------------------------------------------------------------
// <copyright file="DecompositionMatrixExtensions.cs" company="Exul">
//     Copyright (c) Exul. All rights reserved.
// </copyright>
// <author>
//     Exul
// </author>
// -------------------------------------------------------------------------------------------------------------------------------

namespace ExulLibrary.Mathematics.LinearAlgebra.Sequential.DoubleExtensions
{
    #region Usings

    using System;

    using ExulLibrary.Mathematics.LinearAlgebra.Exceptions;

    #endregion

    /// <summary>
    ///     Provides extension methods for <see cref="DecompositionMatrix{T}"/> with <see cref="double"/> type parameter.
    /// </summary>
    public static class DecompositionMatrixExtensions
    {
        #region Methods

        #region public

        /// <summary>
        ///     Solves SLAE with the specified decomposition matrix.
        /// </summary>
        /// <param name="matrix">
        ///     The decomposition matrix.
        /// </param>
        /// <param name="rightHandPart">
        ///     The right-hand part as input and the result as output.
        /// </param>
        /// <exception cref="ArgumentNullException">
        ///     <paramref name="matrix"/> is <see langword="null"/>.
        ///     <para>
        ///         --or--
        ///     </para>
        ///     <para>
        ///         <paramref name="rightHandPart"/> is <see langword="null"/>.
        ///     </para>
        /// </exception>
        /// <exception cref="IncompatibleMatrixVectorException">
        ///     <paramref name="matrix"/> and <paramref name="rightHandPart"/> have incompatible dimensions.
        /// </exception>
        /// <exception cref="NotSupportedDecompositionAlgorithmException">
        ///     Decomposition algorithm specified by <paramref name="matrix"/> is not supported.
        /// </exception>
        public static void Solve(this DecompositionMatrix<double> matrix, DenseVector<double> rightHandPart)
        {
#if SAFE

            if (matrix == null)
            {
                throw new ArgumentNullException("matrix");
            }

            if (rightHandPart == null)
            {
                throw new ArgumentNullException("rightHandPart");
            }

            if (rightHandPart.Length < matrix.Matrix.RowsCount)
            {
                throw new IncompatibleMatrixVectorException(
                    "matrix",
                    matrix.Matrix.RowsCount,
                    matrix.Matrix.ColumnsCount,
                    "rightHandPart",
                    rightHandPart.Length,
                    matrix.Matrix.ColumnsCount);
            }

            if (!((matrix.Algorithm == DecompositionAlgorithm.Diagonal) ||
                  (matrix.Algorithm == DecompositionAlgorithm.LU) ||
                  (matrix.Algorithm == DecompositionAlgorithm.Ldlt)))
            {
                throw new NotSupportedDecompositionAlgorithmException("matrix", matrix.Algorithm);
            }

#endif

            switch (matrix.Algorithm)
            {
                case DecompositionAlgorithm.LU:
                {
                    matrix.Matrix.SolveWithLowTriangleAndDiagonal(rightHandPart);
                    matrix.Matrix.SolveWithHighTriangle(rightHandPart);
                    break;
                }

                case DecompositionAlgorithm.Ldlt:
                {
                    matrix.Matrix.SolveWithLowTriangle(rightHandPart);
                    matrix.Matrix.SolveWithDiagonal(rightHandPart);
                    matrix.Matrix.SolveWithHighTriangle(rightHandPart);
                    break;
                }

                case DecompositionAlgorithm.Diagonal:
                {
                    matrix.Matrix.SolveWithDiagonal(rightHandPart);
                    break;
                }
            }
        }

        #endregion

        #endregion
    }
}